﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Tulde.WindowsPhone.Music
{
    public abstract class AnimationBase
    {
        public event EventHandler AnimationCompleted;

        protected virtual void OnAnimationCompleted(EventArgs e)
        {
            if (AnimationCompleted != null)
                AnimationCompleted(this, e);
        }

        protected virtual string ResourceKey
        {
            get
            {
                return GetType().FullName;
            }
        }

        protected abstract Storyboard CreateStoryboard();
        protected abstract void ApplyValues(Storyboard storyboard, TimeSpan? duration = null);

        public virtual void Apply(FrameworkElement element,TimeSpan? duration = null, Action<object, EventArgs> callback = null)
        {
            if (element == null)
                throw new ArgumentNullException("element");

            Storyboard storyboard = null;

            if (element.Resources.Contains(ResourceKey))
            {
                storyboard = element.Resources[ResourceKey] as Storyboard;
                storyboard.Pause();
            }
            else
            {
                storyboard = CreateStoryboard();
                element.Resources.Add(ResourceKey, storyboard);

                foreach (var timeline in storyboard.Children)
                {
                    Storyboard.SetTarget(timeline, element);
                }
            }

            ApplyValues(storyboard,duration);

            if (callback != null)
                storyboard.Completed += (e, args) =>
                    {
                        callback(e, args);
                    };
            else
            {
                storyboard.Completed += OnStoryboardCompleted;
            }
            storyboard.Begin();
        }

        protected virtual void OnStoryboardCompleted(object sender, EventArgs e)
        {
            OnAnimationCompleted(EventArgs.Empty);
        }
      
       
    }
    public class OpacityAnimation : AnimationBase
    {
        public static TimeSpan DefaultDuration = TimeSpan.FromMilliseconds(750);

        public static TimeSpan Slow = TimeSpan.FromMilliseconds(3000);
        public static TimeSpan Normal = TimeSpan.FromMilliseconds(1500);
        public static TimeSpan Fast = TimeSpan.FromMilliseconds(500);

        public OpacityAnimation(double opacity)
            : this(opacity, DefaultDuration)
        {

        }

        public OpacityAnimation(double opacity, TimeSpan duration)
        {
            Opactity = opacity;
            Duration = duration;
        }

        public double Opactity
        {
            get;
            private set;
        }

        public TimeSpan Duration
        {
            get;
            private set;
        }

        protected override Storyboard CreateStoryboard()
        {
            var storyboard = new Storyboard();

            var opacityAnimation = new DoubleAnimation();

            Storyboard.SetTargetProperty(opacityAnimation, new PropertyPath("(FrameworkElement.Opacity)"));

            storyboard.Children.Add(opacityAnimation);

            return storyboard;
        }

        protected override void ApplyValues(Storyboard storyboard, TimeSpan? duration = null)
        {
            if (storyboard == null)
                throw new ArgumentNullException("storyboard");

            var opacityAnimation = storyboard.Children[0] as DoubleAnimation;

            opacityAnimation.To = Opactity;
            opacityAnimation.Duration = duration?? Duration;
        }
    }

    public static class FrameworkElementExtensions
    {
        public static void FadeOut(this FrameworkElement element, TimeSpan? duration = null, Action<object, EventArgs> callback = null)
        {
            element.Fade(0.0,duration,callback);
        }


        public static void FadeIn(this FrameworkElement element,TimeSpan? duration = null, Action<object, EventArgs> callback = null)
        {
            element.Fade(1.0,duration,callback);
        }


        public static void Fade(this FrameworkElement element, double opacity,TimeSpan? duration = null, Action<object,EventArgs> callback = null)
        {
            new OpacityAnimation(opacity).Apply(element,duration, callback);
        }

        public static void CrossFade(this FrameworkElement elementToFadeOut, FrameworkElement elementToFadeIn, TimeSpan? duration = null, Action<object, EventArgs> callback = null)
        {
            FadeOut(elementToFadeOut,duration);
            FadeIn(elementToFadeIn,duration,callback);
        }
    }
}
